<template>
  <div v-if="visible" class="floating-panel">
    <span class="close-btn" role="button" aria-label="关闭" tabindex="0" @click="handleCancel" @keydown.enter="handleCancel">×</span>
    <div class="floating-panel__header">集合</div>
    <div class="floating-panel__body">
      <el-form ref="formRef" :model="form" label-width="60px" size="small" class="section-form">
        <el-form-item label="区域" prop="region">
          <el-input
            v-model="regionBuffer"
            placeholder="请输入区域（逗号/空格/换行分隔，或直接粘贴 JSON）"
            clearable
            type="textarea"
            :rows="4"
            @keyup.enter="handleConfirm"
            @focus="onFocus"
            @blur="onBlur"
          />
        </el-form-item>
        <div class="form-actions">
          <el-button size="small" @click="resetRegion" :disabled="isEmptyDisplay">重置</el-button>
          <el-button type="primary" size="small" :disabled="isEmptyDisplay" @click="handleConfirm">确认</el-button>
        </div>
      </el-form>
    </div>
  </div>
</template>

<script setup lang="ts">
import { reactive, ref, onMounted, onBeforeUnmount, watch, computed,onUnmounted } from 'vue'
import type { ProjectTreeNode } from '@/store/modules/tree'
import { usePropertyForm } from '../composables/usePropertyForm'
import eventBus from '@/utils/eventBus'

// ------------------ 类型定义 ------------------
interface SelectionPayload { objType: string; result: any[] }
type RegionValue = any[] | SelectionPayload

function isSelectionObject(val: any): val is SelectionPayload {
  return val && typeof val === 'object' && 'objType' in val && Array.isArray(val.result)
}

// 将 region 原始值转换为用于显示的数组
function toDisplayArray(value: RegionValue): any[] {
  if (Array.isArray(value)) return value
  if (isSelectionObject(value)) return value.result
  return []
}

// 格式化到文本框（仅显示数组部分）
function formatRegionDisplay(arr: any[]): string {
  if (!arr || arr.length === 0) return ''
  const simple = arr.every(v => ['string', 'number', 'boolean'].includes(typeof v))
  return simple ? arr.join(', ') : JSON.stringify(arr, null, 0)
}

// 解析用户输入文本 -> 数组
function parseTextToArray(text: string): any[] {
  const raw = text.trim()
  if (!raw) return []
  if ((raw.startsWith('[') || raw.startsWith('{')) && (raw.endsWith(']') || raw.endsWith('}'))) {
    try {
      const parsed = JSON.parse(raw)
      if (Array.isArray(parsed)) return parsed
      return [parsed]
    } catch { /* fallback below */ }
  }
  return raw.split(/[\n\s,]+/).map(s => s.trim()).filter(Boolean)
}

// ------------------ 响应式状态 ------------------
const props = defineProps<{ node?: ProjectTreeNode | null; projectId?: number | string | null }>()
const emit = defineEmits<{ (e: 'confirm'): void; (e: 'cancel'): void }>()
const visible = ref(true)
const form = reactive<{ region: RegionValue }>({ region: [] })
const regionBuffer = ref('')
const isEditing = ref(false)
const formRef = ref()

// 用于跳过重复更新（框选结果频繁）
let lastDisplaySignature = ''
function makeSignature(arr: any[]): string {
  return arr.length + '|' + arr.join('¦')
}

// ------------------ 派生状态 ------------------
const isEmptyDisplay = computed(() => regionBuffer.value.trim() === '')

// ------------------ 初始化与同步 ------------------
function loadFromNode(nodeVal: any) {
  if (nodeVal == null) {
    form.region = []
    regionBuffer.value = ''
  } else {
    // 外部可能已经存的是 SelectionPayload 或数组
    form.region = nodeVal as RegionValue
    const arr = toDisplayArray(form.region)
    regionBuffer.value = formatRegionDisplay(arr)
    broadcastRegion(arr)
  }
  lastDisplaySignature = makeSignature(toDisplayArray(form.region))
}

function broadcastRegion(arr: any[]) {
  if (arr.length > 0) eventBus.emit('regionSetResult', arr)
}

function initFromNode() {
  loadFromNode(props.node?.property?.region)
}

// ------------------ 输入与确认 ------------------
function onFocus() { isEditing.value = true }
function onBlur() { isEditing.value = false; syncBufferToRegion() }

function syncBufferToRegion() {
  const arr = parseTextToArray(regionBuffer.value)
  if (isSelectionObject(form.region)) {
    // 保留 objType 只替换 result
    form.region = { objType: form.region.objType, result: arr }
  } else {
    form.region = arr
  }
  lastDisplaySignature = makeSignature(arr)
}

function handleConfirm() {
  syncBufferToRegion()
  rawConfirm()
  emit('confirm')
}

function resetRegion() {
  if (isSelectionObject(form.region)) {
    form.region = { objType: form.region.objType, result: [] }
  } else {
    form.region = []
  }
  regionBuffer.value = ''
  lastDisplaySignature = ''
}

// ------------------ 框选事件处理 ------------------
function applySelectionPayload(payload: any) {
  // 保存完整对象或数组
  form.region = payload as RegionValue
  const arr = toDisplayArray(form.region)
  const sig = makeSignature(arr)
  if (sig === lastDisplaySignature) return // 跳过重复
  lastDisplaySignature = sig
  regionBuffer.value = formatRegionDisplay(arr)
}

const selectionHandler = (payload: any) => {
  if (!visible.value || payload == null) return
  applySelectionPayload(payload)
}

// ------------------ 外部 Form 封装 ------------------
const { handleConfirm: rawConfirm } = usePropertyForm(form, { node: props.node, projectId: props.projectId, persist: false }, () => {})

// ------------------ 监听与生命周期 ------------------
onMounted(() => {
  initFromNode()
  window.addEventListener('keydown', handleKey)
  eventBus.on('selectionEventsResult', selectionHandler)
})

onBeforeUnmount(() => {
  window.removeEventListener('keydown', handleKey)
  eventBus.off('selectionEventsResult', selectionHandler)
})
// onUnmounted(() => {
//   eventBus.emit('regionSetResultOff', regionBuffer.value)
// })
watch(() => props.node, () => {
  if (!isEditing.value) initFromNode()
})

function handleCancel() {
  visible.value = false
  eventBus.emit('regionSetResultOff', regionBuffer.value)// 取消高亮显示被选中的区域
  emit('cancel')
}
function handleKey(e: KeyboardEvent) {
  if (e.key === 'Escape' && visible.value) handleCancel()
}
</script>

<style scoped lang="scss">
@use './common.scss' as *;

.section-form { display: flex; flex-direction: column; gap: 8px; }
.form-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }
</style>
